home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / commands / view.c < prev   
Encoding:
C/C++ Source or Header  |  1992-08-27  |  13.2 KB  |  479 lines

  1. /* 
  2.  * $Header: /private/postgres/src/commands/RCS/view.c,v 2.11 1992/06/28 03:46:38 mao Exp $
  3.  */
  4.  
  5. #include "access/heapam.h"
  6. #include "catalog/syscache.h"
  7. #include "utils/log.h"
  8. #include "nodes/relation.h"
  9. #include "nodes/relation.a.h"
  10. #include "nodes/primnodes.h"
  11. #include "nodes/primnodes.a.h"
  12. #include "parser/parsetree.h"
  13.  
  14. /* #include "catalog_utils.h" */ 
  15.  
  16. extern Name tname();
  17. void makeRetrieveViewRuleName();
  18.  
  19. Name
  20. attname ( relname , attnum )
  21.      Name relname;
  22.      int attnum;
  23. {
  24.     Relation relptr;
  25.     HeapTuple atp;
  26.     ObjectId reloid;
  27.     Name varname;
  28.  
  29.     relptr = amopenr (relname );
  30.     reloid = RelationGetRelationId ( relptr );
  31.    
  32.     atp = SearchSysCacheTuple ( ATTNUM, reloid, attnum , NULL, NULL );
  33.     if (!HeapTupleIsValid(atp)) {
  34.     elog(WARN, "getattnvals: no attribute tuple %d %d",
  35.          reloid, attnum);
  36.     return(0);
  37.     }
  38.     varname = (Name)&( ((AttributeTupleForm) GETSTRUCT(atp))->attname );
  39.  
  40.     return ( varname );
  41. }
  42.  
  43. /*---------------------------------------------------------------------
  44.  * DefineVirtualRelation
  45.  *
  46.  * Create the "view" relation.
  47.  * `DefineRelation' does all the work, we just provide the correct
  48.  * arguments!
  49.  *
  50.  * If the relation already exists, then 'DefineRelation' will abort
  51.  * the xact...
  52.  *---------------------------------------------------------------------
  53.  */
  54. DefineVirtualRelation (relname , tlist )
  55. Name relname;
  56. List tlist;
  57. {
  58.     List attrList, t, element;
  59.     List parameters;
  60.     TLE    entry;
  61.     Resdom  res;
  62.     Name resname;
  63.     ObjectId restype;
  64.     Name restypename;
  65.  
  66.     /*
  67.      * create a list with one entry per attribute of this relation.
  68.      * Each entry is a two element list. The first element is the
  69.      * name of the attribute (a string) and the second the name of the type
  70.      * (NOTE: a string, not a type id!).
  71.      */
  72.     attrList = LispNil;
  73.     if (!null(tlist)) {
  74.     foreach (t, tlist ) {
  75.         /*
  76.          * find the names of the attribute & its type
  77.          */
  78.         entry = get_entry((TL)t);
  79.         res   = get_resdom(entry);
  80.         resname = get_resname(res);
  81.         restype = get_restype(res);
  82.         restypename = tname(get_id_type(restype));
  83.         element = lispCons(lispString(&restypename->data[0]), LispNil);
  84.         element = lispCons(lispString(&resname->data[0]), element);
  85.         attrList = nappend1(attrList, element);
  86.     }
  87.     } else {
  88.     elog ( WARN, "attempted to define virtual relation with no attrs");
  89.     }
  90.  
  91.     /*
  92.      * now create the parametesr for keys/inheritance etc.
  93.      * All of them are nil...
  94.      */
  95.     parameters = LispNil;
  96.     parameters = lispCons(LispNil, parameters);    /* keys */
  97.     parameters = lispCons(LispNil, parameters);    /* inheritance stuff */
  98.     parameters = lispCons(LispNil, parameters);    /* is indexable */
  99.     parameters = lispCons(LispNil, parameters);    /* archive type */
  100.     parameters = lispCons(LispNil, parameters);    /* heap store */
  101.     parameters = lispCons(LispNil, parameters);    /* archive store */
  102.  
  103.     /*
  104.      * finally create the relation...
  105.      */
  106.     DefineRelation(relname, parameters, attrList);
  107. }    
  108.  
  109. #ifdef BOGUS
  110. -------------------------------------------------------------------------
  111. /*    DefineVirtualRelation2
  112.  *    - takes a relation name and a targetlist
  113.  *    and generates a string "create relation ( ... )"
  114.  *    by taking the attributes and types from the tlist
  115.  *    and reconstructing the attr-list for create.
  116.  *    then calls "pg-eval" to evaluate the creation,
  117.  */
  118. DefineVirtualRelation2 ( relname , tlist )
  119.      Name relname;
  120.      List tlist;
  121. {
  122.     LispValue element;
  123.     static char querybuf[1024];
  124.     char *index = querybuf;
  125.     int i;
  126.  
  127.     for ( i = 0 ; i < 1024 ; i++ ) {
  128.     querybuf[i] = NULL;
  129.     }
  130.  
  131.     sprintf(querybuf,"create %s(",relname );
  132.     index += strlen(querybuf);
  133.     
  134.     if ( ! null ( tlist )) {
  135.     foreach ( element, tlist ) {
  136.         TLE     entry = get_entry((TL)element);
  137.         Resdom     res   = get_resdom(entry);
  138.         Name    resname = get_resname(res);
  139.         ObjectId    restype = get_restype(res);
  140.         Name    restypename = tname(get_id_type(restype));
  141.  
  142.         sprintf(index,"%s = %s,",resname,restypename);
  143.         index += strlen(index);
  144.     }
  145.     *(index-1) = ')';
  146.     
  147.     } else
  148.     elog ( WARN, "attempted to define virtual relation with no attrs");
  149.     pg_eval(querybuf, (char *) NULL, (ObjectId *) NULL, 0);
  150. }    
  151. -------------------------------------------------------------------------
  152. #endif BOGUS
  153.  
  154. List
  155. my_find ( string, list )
  156.      char *string;
  157.      List list;
  158. {
  159.     List i = NULL;
  160.     List retval = NULL;
  161.  
  162.     for( i = list ; i != NULL; i = CDR(i) ) {
  163.     if ( CAR(i) && IsA (CAR(i),LispList)) {
  164.         retval = my_find ( string,CAR(i));
  165.         if ( retval ) 
  166.           break;
  167.     } else if ( CAR(i) && IsA(CAR(i),LispStr) && 
  168.             !strcmp(CString(CAR(i)),string) ) {
  169.         retval = i;
  170.         break;
  171.     } 
  172.     }
  173.     return(retval);
  174. }
  175.  
  176. /*------------------------------------------------------------------
  177.  * makeViewRetrieveRuleName
  178.  *
  179.  * Given a view name, create the name for the 'on retrieve to "view"'
  180.  * rule.
  181.  * This routine is called when defining/removing a view.
  182.  *
  183.  * NOTE: it quarantees that the name is at most 15 chars long
  184.  *------------------------------------------------------------------
  185.  */
  186. void
  187. makeRetrieveViewRuleName(rule_name, view_name)
  188. Name rule_name;
  189. Name view_name;
  190. {
  191.     char buf[100];
  192.  
  193.     /*
  194.      * make sure that no non-null characters follow the
  195.      * '\0' at the end of the string...
  196.      */
  197.     bzero(buf, sizeof(buf));
  198.     sprintf(buf, "_RET%s", view_name);
  199.     buf[15] = '\0';
  200.     bcopy(buf, &(rule_name->data[0]), 16);
  201. }
  202.  
  203. /*-----------------------------------------------------------------------
  204.  * FormViewRetrieveRule
  205.  *
  206.  * Form the "on retrieve to view" rule...
  207.  * If the view definition is:
  208.  *    define mikeolson (...target_list...) where ...qual....
  209.  * the rule will be:
  210.  *      define rule ret_mileolson is
  211.  *    on retrieve to mike_olson do instead
  212.  *    retrieve (...target_list...) where ...qual....
  213.  *
  214.  *-----------------------------------------------------------------------
  215.  */
  216. #ifdef TUPLE_VIEW
  217. List
  218. FormViewRetrieveRule (view_name, view_parse)
  219. Name view_name;
  220. List view_parse;
  221. {
  222.     
  223.     NameData rname;
  224.     List p, q, target, rt;
  225.     List lispCopy();
  226.  
  227.     /*
  228.      * Create a parse tree that corresponds to the suitable
  229.      * tuple level rule...
  230.      */
  231.     p = LispNil;
  232.     /*
  233.      * this is an instance-level rule... (or tuple-level
  234.      * for the traditionalists)
  235.      */
  236.     p = nappend1(p, lispAtom("instance"));
  237.     /*
  238.      * the second item in the list is the so called 'hint' : "(rule nil)"
  239.      */
  240.     p = nappend1(p, lispCons(lispAtom("rule"), lispCons(LispNil, LispNil)));
  241.     /*
  242.      * rule name now...
  243.      */
  244.     makeRetrieveViewRuleName(&rname, view_name);
  245.     p = nappend1(p, lispString(&(rname.data[0])));
  246.     /*
  247.      * The next item is a big one...
  248.      * First the 'event type' (retrieve), then the 'target' (the
  249.      * view relation), then the 'rule qual' (no qualification in this
  250.      * case), then the 'instead' information (yes, this is an instead
  251.      * rule!) and finally the 'rule actions', whish is nothing else from
  252.      * a list containing the view parse!
  253.      */
  254.     q = LispNil;
  255.     q = nappend1(q, lispAtom("retrieve"));
  256.     target = lispCons(lispString(view_name), LispNil);
  257.     q = nappend1(q, target);
  258.     q = nappend1(q, LispNil);
  259.     q = nappend1(q, lispInteger(1));
  260.     q = nappend1(q, lispCons(lispCopy(view_parse), LispNil));
  261.     p = nappend1(p, q);
  262.     /*
  263.      * now our final item, the range table...
  264.      */
  265.     rt = lispCopy(root_rangetable(parse_root(view_parse)));
  266.     p = nappend1(p, rt);
  267.  
  268.     return(p);
  269.  
  270. }
  271. #endif TUPLE_VIEW
  272. List
  273. FormViewRetrieveRule (view_name, view_parse)
  274. Name view_name;
  275. List view_parse;
  276. {
  277.     
  278.     NameData rname;
  279.     List p, q, target, rt;
  280.     List lispCopy();
  281.  
  282.     /*
  283.      * Create a lisp tree that corresponds to the suitable
  284.      * rewrite rule args for DefineQueryRewrite();
  285.      */
  286.     p = LispNil;
  287.     makeRetrieveViewRuleName(&rname, view_name);
  288.     p = nappend1(p, lispString(&(rname.data[0])));           /* rulename   */
  289.     p = nappend1(p,lispAtom("retrieve"));                    /* event_type */
  290.                                                              /* event_obj  */
  291.     p = nappend1(p,lispCons(lispString(&view_name->data[0]),LispNil));
  292.     p = nappend1(p,lispCons(LispNil,LispNil));               /* event_qual */
  293.     p = nappend1(p,lispInteger(1));                          /* is_instead */
  294.     q = nappend1(LispNil, view_parse);
  295.     p = nappend1(p,q);                                       /* (action)   */
  296.     return p;
  297. }
  298. static void
  299. DefineViewRules (view_name, view_parse)
  300. Name view_name;
  301. List view_parse;
  302. {
  303.     List retrieve_rule        = NULL;
  304.     char ruleText[1000];
  305. #ifdef NOTYET
  306.     List replace_rule        = NULL;
  307.     List append_rule        = NULL;
  308.     List delete_rule        = NULL;
  309. #endif
  310.  
  311.     retrieve_rule = 
  312.       FormViewRetrieveRule (view_name, view_parse);
  313.  
  314. #ifdef NOTYET
  315.     
  316.     replace_rule =
  317.       FormViewReplaceRule ( view_name, view_tlist, view_rt, view_qual);
  318.     append_rule = 
  319.       FormViewAppendRule ( view_name, view_tlist, view_rt, view_qual);
  320.     delete_rule = 
  321.       FormViewDeleteRule ( view_name, view_tlist, view_rt, view_qual);
  322.  
  323. #endif
  324.  
  325.     sprintf(ruleText, "retrieve rule for view %s", view_name);
  326.     DefineQueryRewrite(retrieve_rule);
  327. #ifdef TUPLE_VIEW
  328.     prs2DefineTupleRule(retrieve_rule, ruleText);
  329. #endif TUPLE_VIEW
  330. #ifdef NOTYET
  331.     DefineQueryRewrite ( replace_rule );
  332.     DefineQueryRewrite ( append_rule );
  333.     DefineQueryRewrite ( delete_rule );
  334. #endif
  335.  
  336. }     
  337.  
  338. /*---------------------------------------------------------------
  339.  * UpdateRangeTableOfViewParse
  340.  *
  341.  * Update the range table of the given parsetree.
  342.  * This update consists of adding two new entries IN THE BEGINNING
  343.  * of the range table (otherwise the rule system will die a slow,
  344.  * horrible and painful death, and we do not want that now, do we?)
  345.  * one for the CURRENT relation and one for the NEW one (both of
  346.  * them refer in fact to the "view" relation).
  347.  *
  348.  * Of course we must also increase the 'varnos' of all the Var nodes
  349.  * by 2...
  350.  *
  351.  * NOTE: these are destructive changes. It would be difficult to
  352.  * make a complete copy of the parse tree and make the changes
  353.  * in the copy. 'lispCopy' is not enough because it onyl does a high
  354.  * level copy (i.e. the Var nodes remain the same, so the varno offset
  355.  * will update both parsetrees) and I am not confident that
  356.  * 'copyfuncs.c' are bug free...
  357.  *---------------------------------------------------------------
  358.  */
  359. void
  360. UpdateRangeTableOfViewParse(view_name, view_parse)
  361. Name view_name;
  362. List view_parse;
  363. {
  364.     List old_rt;
  365.     List new_rt;
  366.     List root;
  367.     List rt_entry1, rt_entry2;
  368.     List MakeRangeTableEntry();
  369.  
  370.     /*
  371.      * first offset all var nodes by 2
  372.      */
  373.     OffsetVarNodes(view_parse, 2);
  374.  
  375.     /*
  376.      * find the old range table...
  377.      */
  378.     root = parse_root(view_parse);
  379.     old_rt = root_rangetable(root);
  380.  
  381.     /*
  382.      * create the 2 new range table entries and form the new
  383.      * range table...
  384.      * CURRENT first, then NEW....
  385.      */
  386.     rt_entry1 = MakeRangeTableEntry(view_name, LispNil, "*CURRENT*");
  387.     rt_entry2 = MakeRangeTableEntry(view_name, LispNil, "*NEW*");
  388.     new_rt = lispCons(rt_entry2, old_rt);
  389.     new_rt = lispCons(rt_entry1, new_rt);
  390.  
  391.     /*
  392.      * Now the tricky part....
  393.      * Update the range table in place... Be careful here, or
  394.      * hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
  395.      */
  396.     root_rangetable(root) = new_rt;
  397. }
  398.        
  399. /*-------------------------------------------------------------------
  400.  * DefineView
  401.  *
  402.  *    - takes a "viewname", "parsetree" pair and then
  403.  *    1)    construct the "virtual" relation 
  404.  *    2)    commit the command but NOT the transaction,
  405.  *        so that the relation exists
  406.  *        before the rules are defined.
  407.  *    2)    define the "n" rules specified in the PRS2 paper
  408.  *        over the "virtual" relation
  409.  *-------------------------------------------------------------------
  410.  */
  411.  
  412. void
  413. DefineView(view_name, view_parse)
  414. Name view_name;
  415. List view_parse;
  416. {
  417.  
  418.     List view_tlist;
  419.  
  420.     view_tlist = parse_targetlist( view_parse );
  421.  
  422.     /*
  423.      * Create the "view" relation
  424.      * NOTE: if it already exists, the xaxt will be aborted.
  425.      */
  426.     DefineVirtualRelation (view_name ,view_tlist);
  427.  
  428.     /*
  429.      * The relation we have just created is not visible
  430.      * to any other commands running with the same transaction &
  431.      * command id.
  432.      * So, increment the command id counter (but do NOT pfree any
  433.      * memory!!!!)
  434.      */
  435.     CommandCounterIncrement();
  436.  
  437.     /*
  438.      * The range table of 'view_parse' does not contain entries
  439.      * for the "CURRENT" and "NEW" relations.
  440.      * So... add them!
  441.      * NOTE: we make the update in place! After this call 'view_parse' 
  442.      * will never be what it used to be...
  443.      */
  444.     UpdateRangeTableOfViewParse(view_name, view_parse);
  445.     DefineViewRules(view_name, view_parse);
  446. }
  447.  
  448. /*------------------------------------------------------------------
  449.  * RemoveView
  450.  *
  451.  * Remove a view given its name
  452.  *------------------------------------------------------------------
  453.  */
  454. void
  455. RemoveView(view_name)
  456. Name view_name;
  457. {
  458.     NameData rname;
  459.  
  460.     /*
  461.      * first remove all the "view" rules...
  462.      * Currently we only have one!
  463.      */
  464.     makeRetrieveViewRuleName(&rname, view_name);
  465.     RemoveRewriteRule(&rname);
  466. #ifdef TUPLE_VIEW
  467.     prs2RemoveTupleRule(&rname);
  468. #endif TUPLE_VIEW
  469.     /*
  470.      * we don't really need that, but just in case...
  471.      */
  472.     CommandCounterIncrement();
  473.  
  474.     /*
  475.      * now remove the relation.
  476.      */
  477.     RelationNameDestroyHeapRelation(view_name->data);
  478. }
  479.